package com.imedical.strategy;


import com.imedical.entity.RequestDetail;
import com.imedical.enums.CoreConstant;
import com.imedical.exception.DataException;
import com.imedical.util.CommonRequestDataDealUtils;
import com.imedical.util.HtmlToPDFUtils;

import org.springframework.stereotype.Service;

import java.util.Map;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2022/1/19
 */
@SuppressWarnings("AlibabaAvoidComplexCondition")
@Service
@Slf4j
@RequiredArgsConstructor
public class SendHttpRequestStrategy implements SendRequestStrategy {

    @Override
    public Object sendRequest(RequestDetail requestDetail) {
        // 设置URL
        HttpRequest request = new HttpRequest(requestDetail.getUrl());
        // 设置请求方式
        request.setMethod(buildRequestMethod(requestDetail.getRequestMethod()));
        // 设置参数
        buildRequestParams(request, requestDetail);
        // 设置 Authorization 请求头
        if (StrUtil.isNotBlank(requestDetail.getAuthHeader())) {
            request.auth(requestDetail.getAuthHeader());
        }
        // 设置超时时间
        request.timeout(ObjectUtil.isNotEmpty(requestDetail.getTimeout()) ? requestDetail.getTimeout() * 1000 : 30 * 1000);

        log.info("\n================================ 调用第三方接口请求配置 ================================\n" +
                        "URL: {}\n" +
                        "TYPE: {}\n" +
                        "DETAIL: {}" +
                        "====================================================================================="
                , requestDetail.getUrl(), requestDetail.getRequestMethod(), request);

        TimeInterval timer = DateUtil.timer();
        // 请求数据
        String data = "";
        if (!StrUtil.equalsAnyIgnoreCase(requestDetail.getResponseType(), RequestDetail.RESPONSE_TYPE_PDF)) {
            HttpResponse execute = request.execute(requestDetail.getAsync());
            data = execute.body();
            log.info("\n================================ 调用第三方接口请求结果 ================================\n" +
                            "response: {}\n" +
                            "请求用时: {}\n" +
                            "====================================================================================="
                    , execute, timer.intervalPretty());
        }
        // 处理返回数据
        return dealResponseData(data, requestDetail);
    }

    /**
     * 处理返回数据，展示形式和是否脱敏
     *
     * @param body          返回数据
     * @param requestDetail RequestDetail
     * @return Object
     */
    private Object dealResponseData(String body, RequestDetail requestDetail) {
        // 返回类型时DATA
        if (StrUtil.equalsIgnoreCase(requestDetail.getResponseType(), RequestDetail.RESPONSE_TYPE_DATA)) {
            return JSONUtil.isJson(body) ? JSONUtil.parse(body) : body;
        }
        // 返回类型为HTML
        else if (StrUtil.equalsAnyIgnoreCase(requestDetail.getResponseType(), RequestDetail.RESPONSE_TYPE_HTML)) {
            if (StrUtil.equalsAnyIgnoreCase(requestDetail.getDisplayMode(), "HTML") || StrUtil.isBlank(requestDetail.getDisplayMode())) {
                return body;
            }
            HtmlToPDFUtils htmlToPdfUtils = HtmlToPDFUtils.build();
            HtmlToPDFUtils.SimplePDFFileItem fileItem = (HtmlToPDFUtils.SimplePDFFileItem) htmlToPdfUtils.convertPdfFromText(body, UUID.fastUUID().toString());
            String pdfPath = FileUtil.getAbsolutePath(fileItem.getDfosFile());

            CommonRequestDataDealUtils.dealDownloadFile(requestDetail.getDisplayMode(), pdfPath);
            FileUtil.del(StrUtil.removeSuffix(pdfPath, FileUtil.getSuffix(pdfPath)) + "html");
        }
        // 返回类型为PDF
        else if (StrUtil.equalsAnyIgnoreCase(requestDetail.getResponseType(), RequestDetail.RESPONSE_TYPE_PDF)) {
            String pdfPath = CoreConstant.TMP_FILE_DIR + UUID.fastUUID() + ".pdf";
            HttpUtil.downloadFile(requestDetail.getUrl() + "?" + requestDetail.getParam(), pdfPath);
            CommonRequestDataDealUtils.dealDownloadFile(requestDetail.getDisplayMode(), pdfPath);
        }
        return JSONUtil.isJson(body) ? JSONUtil.parse(body) : body;
    }

    /**
     * 设置请求参数
     *
     * @param request       请求对象
     * @param requestDetail 请求信息
     */
    private void buildRequestParams(HttpRequest request, RequestDetail requestDetail) {
        if (StrUtil.isNotBlank(requestDetail.getParamType()) && StrUtil.isNotBlank(requestDetail.getParam())) {
            switch (requestDetail.getParamType().toUpperCase()) {
                case "FORM":
                    if (!JSONUtil.isJsonObj(requestDetail.getParam())) {
                        throw new DataException(StrUtil.format("【paramType = {}】时, param 必须为JSON对象", requestDetail.getParamType()));
                    }
                    JSONObject parseObj = JSONUtil.parseObj(requestDetail.getParam());
                    Map<String, Object> param = MapUtil.newHashMap();
                    parseObj.forEach(param::put);
                    request.form(param);
                    break;
                case "BODY":
                    request.body(requestDetail.getParam());
                    break;
                default:
                    throw new DataException(StrUtil.format("暂未支持【{}】类型传参", requestDetail.getParamType()));
            }
        } else if (StrUtil.isBlank(requestDetail.getParamType()) && StrUtil.isNotBlank(requestDetail.getParam())) {
            throw new DataException(StrUtil.format("参数不为空时, 传参方式不能为空"));
        }
    }

    /**
     * 设置请求类型
     *
     * @param method 请求方式
     * @return 设置的请求方式
     */
    private Method buildRequestMethod(String method) {
        if (StrUtil.isBlank(method)) {
            throw new DataException("当请求类型为【HTTP/HTTPS】时, 请求方式【type】不能为空");
        }
        switch (method.toUpperCase()) {
            case "GET":
                return Method.GET;
            case "POST":
                return Method.POST;
            case "PUT":
                return Method.PUT;
            case "DELETE":
                return Method.DELETE;
            default:
                throw new DataException(StrUtil.format("请求方式【{}】暂未支持", method));
        }
    }

}
